package com.t.bricks.bussiness.controller.wechat;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

import java.io.PrintWriter;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.t.bricks.bussiness.model.wechat.SendMsg;
import com.t.bricks.bussiness.service.wechat.TimingService;
import com.t.bricks.bussiness.service.wechat.WeChatService;
import com.t.bricks.bussiness.util.wechat.MessageUtil;
import com.t.bricks.model.Log;
import com.t.bricks.model.MsgEmity;

/**
 * 微信通讯
 */
@Controller
@Api(value="微信公众号通讯", tags={"微信公众号通讯操作接口"})
@RequestMapping("/wechat/")
public class WeChatController {
		
	/**
	 * #微信公众号的程序域名(本公众号域名)
	 */
	@Value("${wechat.official.account.domain:}")
	private String officialAccountDomain;

	/**
	 * 微信业务实现类
	 */
	@Autowired
	private WeChatService weChatService;

	@Autowired
	private TimingService timingService;

	/**
	 * 微信端验证链接用接口,已经完整,不用改变
	 * 注意:参数都是腾讯方自动提供,不要尝试自己调用这个接口
	 * @param signature 腾讯自动提供,不要尝试去获取,无意义
	 * @param timestamp 时间戳
	 * @param nonce 随机值
	 * @param echostr 正确时的返回值
	 * @return 正确时返回echostr
	 */
	@RequestMapping(value="/msg", method=RequestMethod.GET)
	@ResponseBody
	public String check(@RequestParam("signature") String signature,
						@RequestParam("timestamp") String timestamp,
						@RequestParam("nonce") String nonce,
						@RequestParam("echostr") String echostr) {
		return weChatService.check(signature, timestamp, nonce, echostr);
	}

	/**
	 * 微信端验证链接用接口,已经完整,不用改变(供消费者端调用)
	 * 注意:参数都是腾讯方自动提供,不要尝试自己调用这个接口
	 * @param signature 腾讯自动提供,不要尝试去获取,无意义
	 * @param timestamp 时间戳
	 * @param nonce 随机值
	 * @param echostr 正确时的返回值
	 * @return 正确时返回echostr
	 */
	@RequestMapping(value="/client/msg", method=RequestMethod.GET)
	@ResponseBody
	public MsgEmity checkByClient(@RequestParam("signature") String signature,
						@RequestParam("timestamp") String timestamp,
						@RequestParam("nonce") String nonce,
						@RequestParam("echostr") String echostr) {
		String result = weChatService.check(signature, timestamp, nonce, echostr);
		return new MsgEmity(true, "请求通过", result);
	}
	
	/**
	 * 微信应答:收到用户在公众号中的消息,根据消息进行回应
	 * 注意:整个过程限定在5秒内,否则腾讯会告知用户"服务端错误"
	 * @param request
	 * @param response
	 */
	@RequestMapping(value="/msg", method=RequestMethod.POST)
	@ResponseBody
	public void accpetMessage(HttpServletRequest request, HttpServletResponse response) {
		//response.setCharacterEncoding("utf-8");	//已经在拦截器进行,这里做备注 在响应消息（回复消息给用户）时，也将编码方式设置为UTF-8
		//request.setCharacterEncoding("UTF-8");	//已经在拦截器进行,这里做备注微信服务器POST消息时用的是UTF-8编码，在接收时也要用同样的编码，否则中文会乱码
		
		//将微信请求xml转为map格式，获取所需的参数
		Map<String, String> map = MessageUtil.xmlToMap(request);
		String resultMsg = weChatService.echo(map);//回应处理,一定会成功,不成功也没意义了

		//--将消息返回给对方--//
		PrintWriter out = null;
		try {
			out = response.getWriter();
			out.write(resultMsg);
		} catch (Exception e) {
			Log.error("响应微信客户的消息发生异常:", e.getMessage());
		}
		
		if (out != null) {
			out.close();
		}
	}
	
	/**
	 * 微信应答:收到用户在公众号中的消息,根据消息进行回应(供消费者端调用)
	 * 注意:整个过程限定在5秒内,否则腾讯会告知用户"服务端错误"
	 * @param request
	 * @param response
	 */
	@RequestMapping(value="/client/msg/accpet", method=RequestMethod.POST)
	@ResponseBody
	public MsgEmity accpetMessageByClient(@RequestParam("requestInputStream") String requestInputStream) {
		//Log.debug("接收到微信客户的消息:", requestInputStream);
		
		//将微信请求xml转为map格式，获取所需的参数
		Map<String, String> map = MessageUtil.xmlToMap(requestInputStream);
		String resultMsg = weChatService.echo(map);//回应处理,一定会成功,不成功也没意义了

		return new MsgEmity(true, resultMsg);
	}

	/**
	 * 获取登录页面
	 */
	@RequestMapping(value="/login/view", method={RequestMethod.GET})
	@ResponseBody
	public String loginView() {
		MsgEmity me = weChatService.loginView();
		return me.getData();
	}

	/**
	 * 获取登录页面
	 */
	@RequestMapping(value="/client/login/view", method={RequestMethod.POST})
	@ResponseBody
	public MsgEmity loginViewByClient() {
		return weChatService.loginView();
	}

	/**
	 * 创建自定义菜单
	 */
	@RequestMapping(value="/init/menu", method={RequestMethod.POST, RequestMethod.GET})
	@ResponseBody
	public MsgEmity initMenu() {
		return weChatService.initMenu();
	}

	/**
	 * 页面转发处理
	 * 作用:客户请求进入某个页面时,因页面需要获得用户在页面系统中的信息时需要进行携带参数(如用户ID),而用户ID的获取需要先通过微信关注号进行关联查询
	 * 		因此必须先通过此接口跳转到腾讯的微信服务器 获取到相关的openid,然后跳转到接收openid的接口,最后在接收openid的接口中再次进行转发到jump参数定义的页面
	 * 前提:1.要在微信公众号设置->功能设置->网页授权域名中添加域名; 2.将腾讯提供的MP_verify_XEWuM6WtxWmSIAJH.txt文件放入发布程序的根目录下; 3.设定2个跳转接口,1个用于接收菜单事件,1个用于接收返回openid的接口
	 * @param jump 实际真正要进入的页面地址
	 * @return
	 */
	@RequestMapping(value="/redirect", method={RequestMethod.GET})
	public String redirect(String jump) {
		if (null == jump || "".equals(jump.trim())) {
			return "";//没有跳转,没意义
		}

		jump = jump.replaceAll("/#/", "/%23/");
		return "redirect:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxfbb25b28c11fa245&redirect_uri=http://OFFICIAL_ACCOUNT_DOMAIN/wechat/jump?response_type=code&scope=snsapi_base&state=JUMP_URL&connect_redirect=1#wechat_redirect"
				.replace("OFFICIAL_ACCOUNT_DOMAIN", officialAccountDomain).replace("JUMP_URL", jump);
	}

	/**
	 * 页面转发处理(供消费者端调用)
	 * 作用:客户请求进入某个页面时,因页面需要获得用户在页面系统中的信息时需要进行携带参数(如用户ID),而用户ID的获取需要先通过微信关注号进行关联查询
	 * 		因此必须先通过此接口跳转到腾讯的微信服务器 获取到相关的openid,然后跳转到接收openid的接口,最后在接收openid的接口中再次进行转发到jump参数定义的页面
	 * 前提:1.要在微信公众号设置->功能设置->网页授权域名中添加域名; 2.将腾讯提供的MP_verify_XEWuM6WtxWmSIAJH.txt文件放入发布程序的根目录下; 3.设定2个跳转接口,1个用于接收菜单事件,1个用于接收返回openid的接口
	 * @param jump 实际真正要进入的页面地址
	 * @return
	 */
	@RequestMapping(value="/client/redirect", method={RequestMethod.POST})
	@ResponseBody
	public MsgEmity redirectByClient(String jump) {
		if (null == jump || "".equals(jump.trim())) {
			return new MsgEmity(false, "无意义的请求", "");//没有跳转,没意义
		}
		
		jump = jump.replaceAll("/#/", "/%23/");
		String result = "redirect:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxfbb25b28c11fa245&redirect_uri=http://OFFICIAL_ACCOUNT_DOMAIN/wechat/jump?response_type=code&scope=snsapi_base&state=JUMP_URL&connect_redirect=1#wechat_redirect"
				.replace("OFFICIAL_ACCOUNT_DOMAIN", officialAccountDomain).replace("JUMP_URL", jump);
		
		return new MsgEmity(true, "请求成功", result);
	}
	
	/**
	 * 接收来自微信的授权结果, 与'/redirect'接口有关联
	 * @param code 来自腾讯的请求码
	 * @param state 跳转的页面
	 * @param redirectAttributes 重定向时设置参数
	 * @return
	 */
	@RequestMapping(value="/jump", method=RequestMethod.GET)
    public String jumpView(String code, String state, RedirectAttributes redirectAttributes) {
		MsgEmity me = weChatService.redirect(code, state);
		if (!me.isSuccess()) {
        	return me.getMsg();
        }
		
		redirectAttributes.addAttribute("openid", me.getData());//在页面重定向中夹带参数

        return me.getMsg();//重定向到具体页面
    }
	
	/**
	 * 接收来自微信的授权结果, 与'/redirect'接口有关联(供消费者端调用)
	 * @param code 来自腾讯的请求码
	 * @param state 跳转的页面
	 * @param redirectAttributes 重定向时设置参数
	 * @return
	 */
	@RequestMapping(value="/client/jump", method=RequestMethod.POST)
	@ResponseBody
    public MsgEmity jumpViewByClient(String code, String state) {
		return weChatService.redirect(code, state);
    }
	
	/**
	 * 推送消息
	 * @param sendMsg
	 * @return
	 */
	//[start]
	@ApiOperation(value="新增数据", response=SendMsg.class)
	@ApiResponses({
		@ApiResponse(code=200, message="{\"success\": 布尔值, \"msg\": 文字提示, \"data\": 码值|Json数据对象}"),
		@ApiResponse(code=400, message="错误的请求,请检查路径"),
		@ApiResponse(code=404, message="请求路径没有或页面跳转路径不对"),
		@ApiResponse(code=1000001, message="内部请求密钥错误"),
		@ApiResponse(code=1000002, message="您还没有登录或登录已超时,需要重新登录"),
		@ApiResponse(code=1000003, message="检查登录状态失败,请稍后重试！"),
		@ApiResponse(code=1000004, message="请求的操作不存在,请检查访问地址正确性，如大小写"),
		@ApiResponse(code=1000005, message="响应后在系统内部发生不可预知的错误"),
		@ApiResponse(code=1019000, message="1019000~1999999为拦截器调用方法错误"),
		@ApiResponse(code=8000, message="请求操作的参数为空"),
		@ApiResponse(code=8001, message="内部待转换的类型为空"),
		@ApiResponse(code=8002, message="服务端缺少json转换包的引用"),
		@ApiResponse(code=8003, message="服务端缺少json转换包的引用"),
		@ApiResponse(code=8004, message="待操作的数据不符合格式要求"),
		@ApiResponse(code=8011, message="检查数据时:待存储的数据实体不能为null"),
		@ApiResponse(code=8101, message="检查数据时:数据为null"),
		@ApiResponse(code=8102, message="检查数据时:数据某个值超出最大长度限制"),
		@ApiResponse(code=8103, message="检查数据时:数据某个值为空"),
		@ApiResponse(code=8021, message="验证数据是否重复时:待存储的数据实体不能为null"),
		@ApiResponse(code=8022, message="验证数据是否重复时:没有找到对应的dao实例,请检查代码规范"),
		@ApiResponse(code=8023, message="验证数据是否重复时:无法调用checkRepeatByAdd且发生了异常"),
		@ApiResponse(code=8024, message="验证数据是否重复时:检查数据是否重复失败"),
		@ApiResponse(code=8025, message="验证数据是否重复时:代码错误,checkRepeatByAdd方法返回的结构不是MsgEmity"),
		@ApiResponse(code=8026, message="验证数据是否重复时:数据重复"),
		@ApiResponse(code=8028, message="验证数据是否重复时:检查数据是否重复失败"),
		@ApiResponse(code=8311, message="补充数据时:待存储的数据实体不能为null"),
		@ApiResponse(code=8312, message="补充数据时:设置默认值失败"),
		@ApiResponse(code=7001, message="新增数据失败"),
		@ApiResponse(code=7002, message="新增时发生异常"),
		@ApiResponse(code=7003, message="7003~8998为新增时发生的其它错误")
	})
	//[end]
	@RequestMapping(value="/push/msg", method={RequestMethod.GET, RequestMethod.POST} )
	@ResponseBody
	public MsgEmity pushMsg(@RequestBody SendMsg sendMsg) {
		return weChatService.pushMsg(sendMsg, true);
	}
	
	/**
	 * 激活处理消息的事件,将所有待处理的消息全部进行处理
	 * 专门提供给外部程序触发,比如从数据库中访问触发
	 * @param data 请求内容
	 * @return
	 */
	@RequestMapping(value="/handle/msg", method={RequestMethod.GET, RequestMethod.POST})
	@ResponseBody
	public MsgEmity handleMsg(String data) {
		return timingService.handleMsg(data);
    }
	
}
